import java.io.File;
import java.io.InputStream;
import java.lang.instrument.ClassDefinition;
import java.lang.instrument.Instrumentation;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import com.xhz.Trace;

public abstract class HotDeployer {
    private Result result;
	private Instrumentation inst;
	List<ClassDefinitionWrap> redefineClassWrap = new ArrayList<>();
	
	public HotDeployer(Result result, Instrumentation inst) {
		this.result = result;
		this.inst = inst;
	}
	
	//获取热加载jar包的路径
	protected abstract String getHotDeployJarPath();
	
	public Result exec() {
		try {
			File file = new File(getHotDeployJarPath());
			Trace.info(file.getAbsolutePath());
			if (!file.exists()) {
				result.appendMsg("未找到热加载的jar包");
				result.setResult(false);
				return result;
			}
			result.appendMsg("已找到热加载的jar包:"+getHotDeployJarPath());
			
			JarFile jarFile = new JarFile(file);
			Enumeration<JarEntry> enumeration = jarFile.entries();
			
			while (enumeration.hasMoreElements()) {
				JarEntry entry = enumeration.nextElement();
				String name = entry.getName();
				if (!name.endsWith(".class")) 
					continue;
				String classname = name.replace('/', '.');
				classname = classname.substring(0, classname.lastIndexOf('.'));
				InputStream inputStream = jarFile.getInputStream(entry);
				byte[] bs = Helper.toBytes(inputStream);
				Class<?> cls = null;
				cls = Class.forName(classname);
				if (null == cls)
					continue;
				byte[] originaBs = null;
				InputStream originalInputStream = cls.getResourceAsStream("/"+name);
				if (null != originalInputStream)
					originaBs = Helper.toBytes(originalInputStream);
				redefineClassWrap.add(new ClassDefinitionWrap(cls, bs, originaBs, classname));
			}
			
			for (ClassDefinitionWrap rWrap : redefineClassWrap) {
				inst.redefineClasses(new ClassDefinition(rWrap.getCls(), rWrap.getBs()));
				result.appendMsg("热加载类：ࣺ"+rWrap.getClassname()+"成功");
			}
			
			result.appendMsg("热加载成功");
			jarFile.close();
		} catch(Exception e) {
			e.printStackTrace();
			result.appendMsg("热加载失败");
			result.setResult(false);
		} 
		return result;
	}
}